#include "thread.h"
#include <ucontext.h>
#include <stdio.h>
#include <signal.h>

//////////////////////////////////////////////////////////////////////////////
//            Определяем структуры для реализации списка
typedef struct _Thread {
    ucontext_t context;         //контекст потока
    unsigned int wait_index;    //ожидаемый индекс (lock || signal)

    //указатели на следующий и предыдущий потоки
    struct _Thread* lpNext;
    struct _Thread* lpLast;
} Thread;

typedef Thread* LPThread;

//Определим 3 очереди потоков (активные, заблоченные, ожидающие сигнала)
LPThread ActiveThreads;
LPThread LockedThreads;
LPThread WaitThreads;

//Отдельная очередь удалённые потоки
LPThread DeleteThreads;

//////////////////////////////////////////////////////////////////////////////
//             Вспомогательные функции

// Очистка очереди удалённых потоков
void free_delete_queue(){
    while (!DeleteThreads) {
        if (DeleteThreads->lpNext != DeleteThreads) {
            //выводим поток из очереди
            LPThread lpThread = DeleteThreads->lpNext;
            lpThread->lpLast->lpNext = lpThread->lpNext;
            lpThread->lpNext->lpLast = lpThread->lpLast;
            free(lpThread);
        } else {
            free(DeleteThreads);
            DeleteThreads = 0;
        }
    }
}

//функция перемещения потоков из очереди в очередь
void thread_move(LPThread lpThread, LPThread *To) {
    //выводим поток из текущей очереди
    if (lpThread && lpThread->lpLast && lpThread->lpNext) {
        lpThread->lpLast->lpNext = lpThread->lpNext;
        lpThread->lpNext->lpLast = lpThread->lpLast;
    }

    //Вводим поток в новую очередь
    lpThread->lpLast = (*To)->lpLast;
    lpThread->lpNext = (*To);
    (*To)->lpLast->lpNext = lpThread;
    (*To)->lpLast = lpThread;
    lpThread->context.uc_link = &((*To)->context);
}

//функция исполняющая поток
void thread_function(LPThread lpThread, thread_func_t func, void* arg) {
    //выполняем функцию
    func(arg);
    //перемещаем поток в список удалённых
    thread_move(lpThread, &DeleteThreads);
}



//////////////////////////////////////////////////////////////////////////////

int thread_create(thread_func_t func, void* arg) {
    //Создаём запись для нового потока
    LPThread lpNew = (LPThread) malloc(sizeof(Thread));
    if (!lpNew) {
        #ifdef DEBUG_MODE
        printf("thread_create >> ERROR: Memory access denied. Thread wasn't created.\n");
        #endif
        return -1;
    }

    //получаем контекст
    if (getcontext(&lpNew->context)) {
        #ifdef DEBUG_MODE
        printf("thread_create >> ERROR: Context wasn't got.\n");
        #endif
        free(lpNew);
        return -1;
    }

    //устанавливаем новый стек для контекста
    lpNew->context.uc_stack.ss_sp = malloc(STACK_SIZE * sizeof(char));
    if (lpNew->context.uc_stack.ss_sp) {
        #ifdef DEBUG_MODE
        printf("thread_create >> ERROR: Memory access denied. Stack wasn't created.\n");
        #endif
        free(lpNew);
        return -1;
    }
    lpNew->context.uc_stack.ss_size = STACK_SIZE;
    lpNew->context.uc_stack.ss_flags = 0;

    //создаёмм контекст
    makecontext(&lpNew->context, (void(*)()) thread_function, lpNew, func, arg);
}

int thread_init(thread_func_t func, void* arg) {
    
}























